class Node {
    constructor(name, type) {
        this.attr = {"name": name, "type": type};
        for (let attr in this.attr) {
            this[attr] = this.attr[attr];
        }
        this.args = {};
        this.is_move = false;
        this.out = {};
        this.buttom = [];
        this.above = [];
        this.X = 0;
        this.W = 50;
        this.H = 50;
        this.Y = 0;
        this.center_X = (this.X + this.W) / 2;
        this.center_Y = (this.Y + this.H) / 2;
    };

    setattr(attr, value) {
        this.attr[attr] = value;
    };

    flush() {
        for (let arg in this.attr) {
            this.attr[arg] = null;
            this.attr[arg] = this[arg];
        }
    }

    onChange(e) {
        this.model_node[this.attrType] = this.value;
        this.model_node.flush();
    };

    addButtom(model_node) {
        model_node.above.push(this);
        this.buttom.push(model_node);
    }

    moveto(x, y) {
        this.center_X = x;
        this.center_Y = y;
        this.X = this.center_X - this.W / 2;
        this.Y = this.center_Y - this.H / 2;
    };
}

class Graph {
    constructor(canvas, arguments_label) {
        this.canvas = document.getElementById(canvas);
        this.arguments_label = document.getElementById(arguments_label);
        this.canvas.onmousedown = this.OnMouseDown;
        this.canvas.Graph = this;
        this.canvas.width = this.canvas.parentNode.clientWidth;
        // this.canvas.height = this.canvas.parentNode.clientHeight;
        // console.log(this.canvas.parentNode);
        this.canvas.temp_width = this.canvas.width;
        this.canvas.temp_height = this.canvas.height;
        this.canvas.Graph = this;
        this.context = this.canvas.getContext("2d");
        this.border = true;
        this.nodes = [];
        this.rectW = this.canvas.width / 10;
        this.rectH = this.canvas.height / 10;
    };

    draw() {
        this.redraw();

        if (this.border) this.drawBorder();
        this.drawNodes();
        this.drawNodesBorder();
    };

    redraw() {
        this.context.beginPath();
        this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
        this.context.closePath();
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

    };

    onNodeChange(model_node) {
        while (this.arguments_label.hasChildNodes()) {
            this.arguments_label.removeChild(this.arguments_label.firstChild);
        }

        let addAttrText = function (attr_name, element) {
            let t_tr = document.createElement("tr");
            let t_td_Key = document.createElement("td");
            let t_td_Value = document.createElement("td");
            t_td_Key.appendChild(document.createTextNode(attr_name));
            t_td_Value.appendChild(document.createTextNode(model_node[attr_name]));
            t_tr.appendChild(t_td_Key);
            t_tr.appendChild(t_td_Value);
            element.appendChild(t_tr);
        };
        let addAttrInput = function (attr_name, element) {
            let t_tr = document.createElement("tr");
            let t_td_Key = document.createElement("td");
            let t_td_Value = document.createElement("td");
            let t_td_input = document.createElement("input");
            t_td_input.value = model_node[attr_name];//.appendChild(document.createTextNode());
            t_td_input.onchange = model_node.onChange;
            t_td_input.model_node = model_node;
            t_td_input.attrType = attr_name;
            t_td_Value.appendChild(t_td_input);
            t_td_Key.appendChild(document.createTextNode(attr_name));
            t_tr.appendChild(t_td_Key);
            t_tr.appendChild(t_td_Value);
            element.appendChild(t_tr);
        };
        for (let attr in model_node.attr) {
            switch (attr) {
                case 'type':
                    addAttrText(attr, this.arguments_label);
                    break;
                default:
                    addAttrInput(attr, this.arguments_label);
                    break;
            }
        }
        addAttrText('center_X', this.arguments_label);
        addAttrText('center_Y', this.arguments_label);
    }

    drawAttr() {
        for (let index in this.nodes) {
            let model_node = this.nodes[index];
            this.context.font = "18px bold 黑体";
            this.context.fillStyle = "#ff0";
            this.context.textAlign = "center";
            // this.context.textBaseline = "middle";
            let X = model_node.center_X;
            let Y = model_node.Y;
            let scale = 1;
            for (let attr in model_node.attr) {
                this.context.fillText(model_node.attr[attr], X, Y + 30 * scale);
                scale += 1;
            }
        }
    };

    drawNodesBorder() {
        for (let index in this.nodes) {
            let model_node = this.nodes[index];
            this.context.lineWidth = 8;
            this.context.beginPath();

            this.context.moveTo(model_node.X, model_node.Y);
            this.context.lineTo(model_node.X + model_node.W, model_node.Y);
            //
            this.context.moveTo(model_node.X + model_node.W, model_node.Y);
            this.context.lineTo(model_node.X + model_node.W, model_node.Y + model_node.H);

            this.context.moveTo(model_node.X + model_node.W, model_node.Y + model_node.H);
            this.context.lineTo(model_node.X, model_node.Y + model_node.H);

            this.context.moveTo(model_node.X, model_node.Y + model_node.H);
            this.context.lineTo(model_node.X, model_node.Y);
            this.context.strokeStyle = 'red';
            this.context.stroke();
            this.context.closePath();

        }
    };

    drawNodes() {
        for (let index in this.nodes) {
            let model_node = this.nodes[index];
            let scale = 1;
            for (let attr in model_node.attr) {
                model_node.H = scale * 30 * 1.5;
                scale += 1;
            }
            this.context.rect(model_node.X, model_node.Y, model_node.W, model_node.H);
            this.context.fillStyle = "green";
            this.context.fill();
        }
        this.drawAttr();

    };

    drawBorder() {
        this.context.lineWidth = .5;
        this.context.beginPath();
        for (let i = 0; i < this.canvas.width; i++) {
            this.context.moveTo(this.rectW * i, 0);
            this.context.lineTo(this.rectW * i, this.canvas.height);
        }
        for (let i = 0; i < this.canvas.height; i++) {
            this.context.moveTo(0, this.rectH * i);
            this.context.lineTo(this.canvas.width, this.rectH * i);
        }
        this.context.strokeStyle = 'black';

        this.context.stroke();
        this.context.closePath();

    }

    decorator() {
        console.log(this.a);
    };

    toJson() {

    };

    loads(graph) {

    }

    addNode(model_node) {
        //尾追加
        this.nodes.push(model_node);
        for (let index in this.nodes) {
            let model_node = this.nodes[index];
            model_node.X = 0;
            model_node.Y = 0;
        }
        for (let index in this.nodes) {
            let model_node = this.nodes[index];
            model_node.X = model_node.X + model_node.W * index;
            model_node.Y = model_node.Y + model_node.W * index;
            model_node.center_X = model_node.X + model_node.W / 2;
            model_node.center_Y = model_node.Y + model_node.H / 2;
        }
    }

    OnMouseUp(e) {
        this.Graph.draw();
        let x = e.clientX;
        let y = e.clientY;
        for (let index in this.Graph.nodes) {
            let model_node = this.Graph.nodes[index];
            if (x > model_node.X && x < (model_node.X + model_node.W) &&
                y > model_node.Y && x < (model_node.Y + model_node.H)) {
            }
            model_node.is_move = false;

        }
        this.onmousemove = null;
        this.onmouseup = null;
    }

    OnMouseDown(e) {
        this.Graph.draw();
        let x = e.offsetX;
        let y = e.offsetY;
        for (let index in this.Graph.nodes) {
            let model_node = this.Graph.nodes[index];
            // console.log(x, y, model_node.X, model_node.X + model_node.W, model_node.Y + model_node.H);

            if (x > model_node.X && x < (model_node.X + model_node.W) &&
                y > model_node.Y && y < (model_node.Y + model_node.H)) {

                model_node.is_move = true;
                this.Graph.onNodeChange(model_node);
                break;
            }

        }
        this.onmousemove = function (e) {
            this.Graph.draw();
            let x = e.offsetX;
            let y = e.offsetY;
            // console.log(x, y);
            for (let index in this.Graph.nodes) {
                let model_node = this.Graph.nodes[index];
                if (model_node.is_move) {
                    this.Graph.onNodeChange(model_node);
                    model_node.moveto(x, y);
                }
            }
        };

        this.onmouseup = this.Graph.OnMouseUp;


    };
}
